/* ============================================================
 * This code is part of the "apex-lang" open source project avaiable at:
 * 
 *      http://code.google.com/p/apex-lang/
 *
 * This code is licensed under the Apache License, Version 2.0.  You may obtain a 
 * copy of the License at:
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * ============================================================
 */
@IsTest
private class StringUtilsTest {

    private static testmethod void testAbbreviateTwoArgs(){
        assertAbbreviateTwoArgs(null,         -1, null,         false);
        assertAbbreviateTwoArgs('',         4,     '',            false);
        assertAbbreviateTwoArgs('abcdefg',     6,     'abc...',    false);
        assertAbbreviateTwoArgs('abcdefg',     7,     'abcdefg',    false);
        assertAbbreviateTwoArgs('abcdefg',     8,     'abcdefg',     false);
        assertAbbreviateTwoArgs('abcdefg',     4,     'a...',     false);
        assertAbbreviateTwoArgs('abcdefg',     3,     null,         true);
    }    
     
    private static void assertAbbreviateTwoArgs(String str, Integer maxWidth, 
        String expected, Boolean excepExpected){

        String actual = null;
        Boolean excepActual = false;
        try{
            actual = StringUtils.abbreviate(str,maxWidth);
        } catch (IllegalArgumentException e){
            excepActual = true;
        }
        if(excepExpected && excepActual){
            return;
        }
        System.assert(excepExpected == excepActual, 'StringUtils.abbreviate(\'' 
            + str + '\',' + maxWidth + ') ' 
            + (excepExpected ? 'did not throw' : 'unexpectedly threw') 
            + ' IllegalArgumentException');
        if(!excepExpected && !excepActual){
            System.assert(actual==expected, 'StringUtils.abbreviate(\'' + str + '\',' 
                + maxWidth + ') returned ' + actual + '; expected ' + expected);
        }
    }
    
    private static testmethod void testAbbreviateThreeArgs(){
        assertAbbreviateThreeArgs(null,                 -1,    -1,     null,             false);
        assertAbbreviateThreeArgs('',                     0,     4,         '',                false);
        assertAbbreviateThreeArgs('abcdefghijklmno',    -1, 10,     'abcdefg...',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     0,     10,     'abcdefg...',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     1,     10,     'abcdefg...',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     4,     10,     'abcdefg...',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     5,     10,     '...fghi...',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     6,     10,     '...ghij...',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     8,     10,     '...ijklmno',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     10, 10,     '...ijklmno',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     12, 10,     '...ijklmno',    false);
        assertAbbreviateThreeArgs('abcdefghijklmno',     20, 10,     '...ijklmno',    false);
        assertAbbreviateThreeArgs('abcdefghij',         0,     3,        null,            true);
        assertAbbreviateThreeArgs('abcdefghij',         5,     6,        null,            true);
    }    
    
    private static void assertAbbreviateThreeArgs(String str, Integer offset, Integer maxWidth, 
        String expected, Boolean excepExpected){

        String actual = null;
        Boolean excepActual = false;
        try{
            actual = StringUtils.abbreviate(str,offset,maxWidth);
        } catch (IllegalArgumentException e){
            excepActual = true;
        }
        if(excepExpected && excepActual){
            return;
        }
        System.assert(excepExpected == excepActual, 'StringUtils.abbreviate(\'' 
            + str + '\',' + offset + ',' + maxWidth + ') ' 
            + (excepExpected ? 'did not throw' : 'unexpectedly threw') 
            + ' IllegalArgumentException');
        if(!excepExpected && !excepActual){
            System.assert(actual==expected, 'StringUtils.abbreviate(\'' + str + '\',' 
                + offset + ',' + maxWidth + ') returned ' + actual + '; expected ' + expected);
        }
    }
 
    private static testmethod void testIndexOfAny(){
        //test: global static int indexOfAny(String str, String searchChars) {
        assertIndexOfAny(null, null, -1);
        assertIndexOfAny('', null, -1);
        assertIndexOfAny(null, '', -1);
        assertIndexOfAny('zzabyycdxx', 'za', 0);
        assertIndexOfAny('zzabyycdxx', 'by', 3);
        assertIndexOfAny('aba','z', -1);
    }    
    
    private static void assertIndexOfAny(String str, String searchChars, Integer expected){
        Integer actual = StringUtils.indexOfAny(str,searchChars);
        System.assert(actual==expected, 'StringUtils.indexOfAny(\'' + str + '\',' 
            + searchChars + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
     private static testmethod void testLastIndexOfAny(){
        //test: global static Integer lastIndexOfAny(String str, String[] searchStrs) {
        assertLastIndexOfAny(null, null, -1);
        assertLastIndexOfAny('', null, -1);
        assertLastIndexOfAny(null, new String[]{}, -1);
        assertLastIndexOfAny(null, new String[]{null}, -1);
        assertLastIndexOfAny('', new String[]{null}, -1);
        assertLastIndexOfAny('zzabyycdxx', new String[]{'ab','cd'}, 6);
        assertLastIndexOfAny('zzabyycdxx', new String[]{'cd','ab'}, 6);
        assertLastIndexOfAny('zzabyycdxx', new String[]{'mn','op'}, -1);
        assertLastIndexOfAny('zzabyycdxx', new String[]{'mn','op'}, -1);
        assertLastIndexOfAny('zzabyycdxx', new String[]{'mn',''}, 10);
    }
    
    private static void assertLastIndexOfAny(String str, String[] searchStrs, Integer expected){
        Integer actual = StringUtils.lastIndexOfAny(str,searchStrs);
        System.assert(actual==expected, 'StringUtils.lastIndexOfAny(\'' + str + '\',' 
            + ArrayUtils.toString(searchStrs) + ') returned ' + actual + '; expected ' + expected);
    }
    
    private static testmethod void testLastIndexOfTwoArgs(){
        //test: global static Integer lastIndexOf(String str, String searchStr) {
        assertLastIndexOfTwoArgs(null, '', -1);
        assertLastIndexOfTwoArgs('', null, -1);
        assertLastIndexOfTwoArgs('', '', 0);
        assertLastIndexOfTwoArgs('aabaabaa', 'a', 7);
        assertLastIndexOfTwoArgs('aabaabaa', 'b', 5);
        assertLastIndexOfTwoArgs('aabaabaa', 'ab', 4);
        assertLastIndexOfTwoArgs('aabaabaa', '', 8);
    }    
    
    private static void assertLastIndexOfTwoArgs(String str, String searchStr, Integer expected){
        Integer actual = StringUtils.lastIndexOf(str,searchStr);
        System.assert(actual==expected, 'StringUtils.lastIndexOf(\'' + str + '\',\'' 
            + searchStr + '\') returned ' + actual + '; expected ' + expected);
    }
    
    private static testmethod void testLastIndexOfThreeArgs(){
        //test: global static Integer lastIndexOf(String str, String searchStr, Integer startPos) {
        assertLastIndexOfThreeArgs(null, null, -1, -1);
        assertLastIndexOfThreeArgs('', null, -1, -1);
        assertLastIndexOfThreeArgs('aabaabaa', 'a', 8, 7);
        assertLastIndexOfThreeArgs('aabaabaa', 'b', 8, 5);
        assertLastIndexOfThreeArgs('aabaabaa', 'ab', 8, 4);
        assertLastIndexOfThreeArgs('aabaabaa', 'b', 9, 5);
        assertLastIndexOfThreeArgs('aabaabaa', 'b', -1, -1);
        assertLastIndexOfThreeArgs('aabaabaa', 'a', 0, 0);
        assertLastIndexOfThreeArgs('aabaabaa', 'b', 0, -1);
    }
    
    private static void assertLastIndexOfThreeArgs(String str, String searchStr, Integer startPos, Integer expected){
        Integer actual = StringUtils.lastIndexOf(str,searchStr,startPos);
        System.assert(actual==expected, 'StringUtils.lastIndexOf(\'' + str + '\',\'' 
            + searchStr + '\',' + startPos + ') returned ' + actual + '; expected ' + expected);
    }
    
    private static testmethod void testIndexOfAnyStringArray(){
        //test: global static Integer indexOfAny(String str, String[] searchStrs) {
        assertIndexOfAnyStringArray(null, null, -1);
        assertIndexOfAnyStringArray(null, new String[]{}, -1);
        assertIndexOfAnyStringArray('zzabyycdxx', new String[]{null}, -1);
        assertIndexOfAnyStringArray('zzabyycdxx', new String[]{'ab','cd'}, 2);
        assertIndexOfAnyStringArray('zzabyycdxx', new String[]{'cd','ab'}, 2);
        assertIndexOfAnyStringArray('zzabyycdxx', new String[]{'mn','op'}, -1);
        assertIndexOfAnyStringArray('zzabyycdxx', new String[]{'zab','aby'}, 1);
        assertIndexOfAnyStringArray('zzabyycdxx', new String[]{''}, 0);
        assertIndexOfAnyStringArray('', new String[]{''}, 0);
        assertIndexOfAnyStringArray('', new String[]{'a'}, -1);
    }    
    
    private static void assertIndexOfAnyStringArray(String str, String[] searchStrs, Integer expected){
        Integer actual = StringUtils.indexOfAny(str,searchStrs);
        System.assert(actual==expected, 'StringUtils.indexOfAny(\'' + str + '\',' 
            + ArrayUtils.toString(searchStrs) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }

    private static testmethod void testCenterTwoArgs(){
        assertCenterTwoArgs(null,     -1,    null);
        assertCenterTwoArgs('',     4,    '    ');
        assertCenterTwoArgs('ab',     -1,    'ab');
        assertCenterTwoArgs('ab',     4,    ' ab ');
        assertCenterTwoArgs('abcd', 2,    'abcd');
        assertCenterTwoArgs('a',     4,    ' a  ');
    }    
    
    private static void assertCenterTwoArgs(String str, Integer size, String expected){
        String actual = StringUtils.center(str,size);
        System.assert(actual==expected, 'StringUtils.center(\'' + str + '\',' 
            + size + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testChompOneArg(){
        assertChompOneArg(null,                null);
        assertChompOneArg('',                '');
        assertChompOneArg('abc \r',            'abc ');
        assertChompOneArg('abc\n',            'abc');
        assertChompOneArg('abc\r\n',        'abc');
        assertChompOneArg('abc\r\n\r\n',    'abc\r\n');
        assertChompOneArg('abc\n\r',        'abc\n');
        assertChompOneArg('abc\n\rabc',        'abc\n\rabc');
        assertChompOneArg('\t',                '\t');
        assertChompOneArg('\r',                '');
        assertChompOneArg('\n',                '');
        assertChompOneArg('\r\n',            '');
    }    
    
    private static void assertChompOneArg(String str, String expected){
        String actual = StringUtils.chomp(str);
        System.assert(actual==expected, 'StringUtils.chomp(\'' + str + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testChompTwoArgs(){
        assertChompTwoArgs(null,         null,         null);
        assertChompTwoArgs('',             null,         '');
        assertChompTwoArgs('foobar',     'bar',         'foo');
        assertChompTwoArgs('foobar',     'baz',         'foobar');
        assertChompTwoArgs('foo',        'foo',         '');
        assertChompTwoArgs('foo ',         'foo',         'foo ');
        assertChompTwoArgs(' foo',         'foo',         ' ');
        assertChompTwoArgs('foo',         'foooo',     'foo');
        assertChompTwoArgs('foo',         '',         'foo');
        assertChompTwoArgs('foo',         null,         'foo');
    }    
    
    private static void assertChompTwoArgs(String str, String separator, String expected){
        String actual = StringUtils.chomp(str,separator);
        System.assert(actual==expected, 'StringUtils.chomp(\'' + str + '\', \'' + separator + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }
    
    
    private static testmethod void testCenterThreeArgs(){
        assertCenterThreeArgs(null,     -1, null,     null);
        assertCenterThreeArgs('',         4,     ' ',     '    ');
        assertCenterThreeArgs('ab',     -1, ' ',     'ab');
        assertCenterThreeArgs('ab',     4,     ' ',     ' ab ');
        assertCenterThreeArgs('abcd',     2,     ' ',     'abcd');
        assertCenterThreeArgs('a',         4,     ' ',     ' a  ');
        assertCenterThreeArgs('a',         4,     'yz',     'yayz');
        assertCenterThreeArgs('abc',     7,     null,     '  abc  ');
        assertCenterThreeArgs('abc',     7,     '',     '  abc  ');
    }    
    
    private static void assertCenterThreeArgs(String str, Integer size, String padStr, String expected){
        String actual = StringUtils.center(str,size, padStr);
        System.assert(actual==expected, 'StringUtils.center(\'' + str + '\',' 
            + size + ',\'' + padStr + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testChop(){
        assertChop(null,        null);
        assertChop('',             '');
        assertChop('abc \r',     'abc ');
        assertChop('abc\n',     'abc');
        assertChop('abc\r\n',     'abc');
        assertChop('abc',         'ab');
        assertChop('abc\nabc',     'abc\nab');
        assertChop('a',         '');
        assertChop('\r',         '');
        assertChop('\n',         '');
        assertChop('\r\n',         '');
    }    
    
    private static void assertChop(String str, String expected){
        String actual = StringUtils.chop(str);
        System.assert(actual==expected, 'StringUtils.chop(\'' + str + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testContainsAny(){
        assertContainsAny(null,         null,     false);
        assertContainsAny('',             null,     false);
        assertContainsAny(null,         null,     false);
        assertContainsAny(null,         '',     false);
        assertContainsAny('zzabyycdxx', 'za',     true);
        assertContainsAny('zzabyycdxx', 'by',     true);
        assertContainsAny('aba',        'z',     false);
    }    
    
    private static void assertContainsAny(String str, String searchChars, Boolean expected){
        Boolean actual = StringUtils.containsAny(str,searchChars);
        System.assert(actual==expected, 'StringUtils.containsAny(\'' + str + '\',\'' + searchChars + '\') returned ' 
            + actual);
    }
    
    
    private static testmethod void testContainsNone(){
        //test: global static boolean containsNone(String str, String invalidChars) {
        assertContainsNone(null,     null,     true);
        assertContainsNone(null,     null,     true);
        assertContainsNone('',         null,     true);
        assertContainsNone('ab',     '',     true);
        assertContainsNone('abab',     'xyz',     true);
        assertContainsNone('ab1',     'xyz',     true);
        assertContainsNone('abz',     'xyz',     false);
    }    
    
    private static void assertContainsNone(String str, String invalidChars, Boolean expected){
        Boolean actual = StringUtils.containsNone(str,invalidChars);
        System.assert(actual==expected, 'StringUtils.containsNone(\'' + str + '\',\'' + invalidChars + '\') returned ' 
            + actual);
    }
    
    private static testmethod void testContainsOnly(){
        //test: global static boolean containsOnly(String str, String valid) {
        assertContainsOnly(null,     null,    false);
        assertContainsOnly(null,     null,    false);
        assertContainsOnly('',         null,    false);
        assertContainsOnly('',         '',        true);
        assertContainsOnly('ab',     '',        false);
        assertContainsOnly('abab',     'abc',    true);
        assertContainsOnly('ab1',     'abc',    false);
        assertContainsOnly('abz',     'abc',     false);
    }    
    
    private static void assertContainsOnly(String str, String valid, Boolean expected){
        Boolean actual = StringUtils.containsOnly(str,valid);
        System.assert(actual==expected, 'StringUtils.containsOnly(\'' + str + '\',\'' + valid + '\') returned ' 
            + actual);
    }
    
    private static testmethod void testCountMatches(){
        //test: global static Integer countMatches(String str, String sub) {
        assertCountMatches(null, null, 0);
        assertCountMatches('', null, 0);
        assertCountMatches('abba', null, 0);
        assertCountMatches('abba', '', 0);
        assertCountMatches('abba', 'a', 2);
        assertCountMatches('abba', 'ab', 1);
        assertCountMatches('abba', 'xxx', 0);
    }    
    
    private static void assertCountMatches(String str, String sub, Integer expected){
        Integer actual = StringUtils.countMatches(str,sub);
        System.assert(actual==expected, 'StringUtils.countMatches(\'' + str + '\',\'' + sub + '\') returned ' 
            + actual + '; expected ' + expected);
    }

    private static testmethod void testDefaultIfEmpty(){
        //test: global static String defaultIfEmpty(String str, String defaultStr) {
        assertDefaultIfEmpty(null, 'NULL', 'NULL');
        assertDefaultIfEmpty('', 'NULL', 'NULL');
        assertDefaultIfEmpty('bat', 'NULL', 'bat');
    }    
    
    private static void assertDefaultIfEmpty(String str, String defaultStr, String expected){
        String actual = StringUtils.defaultIfEmpty(str,defaultStr);
        System.assert(actual==expected, 'StringUtils.defaultIfEmpty(\'' + str + '\',\'' + defaultStr + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testDefaultStringOneArg(){
        //test: global static String defaultString(String str) {
        assertDefaultStringOneArg(null, '');
        assertDefaultStringOneArg('', '');
        assertDefaultStringOneArg('bat', 'bat');
    }    
    
    private static void assertDefaultStringOneArg(String str, String expected){
        String actual = StringUtils.defaultString(str);
        System.assert(actual==expected, 'StringUtils.defaultString(\'' + str + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testDefaultStringTwoArgs(){
        //test: global static String defaultString(String str, String defaultStr) {
        assertDefaultStringTwoArgs(null, 'NULL', 'NULL');
        assertDefaultStringTwoArgs('', 'NULL', '');
        assertDefaultStringTwoArgs('bat', 'NULL', 'bat');
    }    
    
    private static void assertDefaultStringTwoArgs(String str, String defaultStr, String expected){
        String actual = StringUtils.defaultString(str,defaultStr);
        System.assert(actual==expected, 'StringUtils.defaultString(\'' + str + '\',\'' + defaultStr + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }
    

    private static testmethod void testDeleteWhitespace(){
        //test: global static String deleteWhitespace(String str) {
        assertDeleteWhitespace(null,             null);
        assertDeleteWhitespace('',                 '');
        assertDeleteWhitespace('abc',             'abc');
        assertDeleteWhitespace('   ab  c  ',     'abc');
    }    
    
    private static void assertDeleteWhitespace(String str, String expected){
        String actual = StringUtils.deleteWhitespace(str);
        System.assert(actual==expected, 'StringUtils.deleteWhitespace(\'' + str + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }

    private static testmethod void testDifference(){
        //test: global static String difference(String str1, String str2) {
        assertDifference(null,         null,         null);
        assertDifference('',         null,         '');
        assertDifference('',         '',         '');
        assertDifference('',         'abc',         'abc');
        assertDifference('abc',     '',         '');
        assertDifference('abc',     'abc',         '');
        assertDifference('ab',         'abxyz',     'xyz');
        assertDifference('abcde',     'abxyz',    'xyz');
        assertDifference('abcde',     'xyz',         'xyz');
    }    
    
    private static void assertDifference(String str1, String str2, String expected){
        String actual = StringUtils.difference(str1,str2);
        System.assert(actual==expected, 'StringUtils.difference(\'' + str1 + '\',\'' + str2 + '\') returned \'' 
            + actual + '\'; expected \'' + expected + '\'');
    }



    private static testmethod void testEquals(){
        //test: global static Boolean equals(String str1, String str2) {
        assertEquals(null,     null,     true);
        assertEquals(null,     'abc',     false);
        assertEquals('abc', null,     false);
        assertEquals('abc', 'abc',     true);
        assertEquals('abc', 'ABC',     false);
    }    
    
    private static void assertEquals(String str1, String str2, Boolean expected){
        Boolean actual = StringUtils.equals(str1,str2); 
        System.assert(actual==expected, 'StringUtils.equals(\'' + str1 + '\',\'' + str2 + '\') returned ' + actual);
    }

    private static testmethod void testEqualsIgnoreCase(){
        //test: global static Boolean equalsIgnoreCase(String str1, String str2) {
        assertEqualsIgnoreCase(null,     null,     true);
        assertEqualsIgnoreCase(null,     'abc',     false);
        assertEqualsIgnoreCase('abc',     null,     false);
        assertEqualsIgnoreCase('abc',     'abc',     true);
        assertEqualsIgnoreCase('abc',     'ABC',     true);
    }    
    
    private static void assertEqualsIgnoreCase(String str1, String str2, Boolean expected){
        Boolean actual = StringUtils.equalsIgnoreCase(str1,str2);
        System.assert(actual==expected, 'StringUtils.equalsIgnoreCase(\'' + str1 + '\',\'' + str2 + '\') returned ' + actual);
    }

    private static testmethod void testIndexOf(){
        //test: global static Integer indexOf(String str, String searchStr) {
        assertIndexOf(null,         null,     -1);
        assertIndexOf('',             null,     -1);
        assertIndexOf('aabaabaa',     'a',     0);
        assertIndexOf('aabaabaa',     'b',    2);
     }    
    
    private static void assertIndexOf(String str1, String searchStr, Integer expected){
        Integer actual = StringUtils.indexOf(str1,searchStr);
        System.assert(actual==expected, 'StringUtils.indexOf(\'' + str1 + '\',\'' + searchStr + '\') returned ' 
            + actual + '; expected ' + expected);
    }

    private static testmethod void testIndexOfDifference(){
        //test: global static Integer indexOfDifference(String str1, String str2) {
        assertIndexOfDifference(null,         null,         -1);
        assertIndexOfDifference(null,         '',         0);
        assertIndexOfDifference('',         null,         0);
        assertIndexOfDifference('',         '',         -1);
        assertIndexOfDifference('',         'abc',         0);
        assertIndexOfDifference('abc',         '',         0);
        assertIndexOfDifference('abc',         'abc',         -1);
        assertIndexOfDifference('ab',         'abxyz',     2);
        assertIndexOfDifference('abcde',     'abxyz',     2);
        assertIndexOfDifference('abcde',     'xyz',         0);
    }    
    
    private static void assertIndexOfDifference(String str1, String str2, Integer expected){
        Integer actual = StringUtils.indexOfDifference(str1,str2);
        System.assert(actual==expected, 'StringUtils.indexOfDifference(\'' + str1 + '\',\'' + str2 + '\') returned ' 
            + actual + '; expected ' + expected);
    }
    
    private static testmethod void testIndexOfAnyBut(){
        //test: global static int indexOfAnyBut(String str, String searchChars) {
        assertIndexOfAnyBut(null,             null,    -1);
        assertIndexOfAnyBut('',             null,    -1);
        assertIndexOfAnyBut(null,             null,    -1);
        assertIndexOfAnyBut(null,             '',        -1);
        assertIndexOfAnyBut('zzabyycdxx',     'za',    3);
        assertIndexOfAnyBut('zzabyycdxx',     '',        0);
        assertIndexOfAnyBut('aba',            'ab',    -1);
    }    
    
    private static void assertIndexOfAnyBut(String str, String searchChars, Integer expected){
        Integer actual = StringUtils.indexOfAnyBut(str,searchChars);
        System.assert(actual==expected, 'StringUtils.indexOfAnyBut(\'' + str + '\',\'' + searchChars + '\') returned ' 
            + actual + '; expected ' + expected);
    }
    
    private static testmethod void testLowerCase(){
        assertLowerCase(null, null);
        assertLowerCase('ABC', 'abc');
        assertLowerCase('abc', 'abc');
        assertLowerCase('aBc', 'abc');
    }    
    
    private static void assertLowerCase(String str, String expected){
        String actual = StringUtils.lowerCase(str);
        System.assert(actual==expected, 'StringUtils.lowerCase(\'' + str + '\') returned ' + actual);
    }
    
    private static testmethod void testUpperCase(){
        assertUpperCase(null, null);
        assertUpperCase('ABC', 'ABC');
        assertUpperCase('abc', 'ABC');
        assertUpperCase('aBc', 'ABC');
    }    
    
    private static void assertUpperCase(String str, String expected){
        String actual = StringUtils.upperCase(str);
        System.assert(actual==expected, 'StringUtils.upperCase(\'' + str + '\') returned ' + actual);
    }
    
    private static testmethod void testCapitalize(){
        assertCapitalize(null, null);
        assertCapitalize('ABC', 'ABC');
        assertCapitalize('abc', 'Abc');
        assertCapitalize('aBc', 'ABc');
    }    
    
    private static void assertCapitalize(String str, String expected){
        String actual = StringUtils.capitalize(str);
        System.assert(actual==expected, 'StringUtils.capitalize(\'' + str + '\') returned ' + actual);
    }
    
    private static testmethod void testUncapitalize(){
        assertUncapitalize(null, null);
        assertUncapitalize('ABC', 'aBC');
        assertUncapitalize('abc', 'abc');
        assertUncapitalize('aBc', 'aBc');
    }    
    
    private static void assertUncapitalize(String str, String expected){
        String actual = StringUtils.uncapitalize(str);
        System.assert(actual==expected, 'StringUtils.uncapitalize(\'' + str + '\') returned ' + actual);
    }
    
    private static testmethod void testSwapCase(){
        assertSwapCase(null, null);
        assertSwapCase('', '');
        assertSwapCase('The dog has a BONE', 'tHE DOG HAS A bone');
    }    
    
    private static void assertSwapCase(String str, String expected){
        String actual = StringUtils.swapCase(str);
        System.assert(actual==expected, 'StringUtils.swapCase(\'' + str + '\') returned ' + actual);
    }
    
    private static testmethod void testIsEmpty(){
        assertIsEmpty(null,     true);
        assertIsEmpty('',        true);
        assertIsEmpty(' ',        false);
        assertIsEmpty('bob',    false);
        assertIsEmpty('  bob  ',false);
    }    
    
    private static void assertIsEmpty(String str, Boolean expected){
        Boolean actual = StringUtils.IsEmpty(str);
        System.assert(actual==expected, 'StringUtils.IsEmpty(\'' + str + '\') returned ' + actual);
    }
    
    private static testmethod void testIsNotEmpty(){
        assertIsNotEmpty(null,         false);
        assertIsNotEmpty('',        false);
        assertIsNotEmpty(' ',        true);
        assertIsNotEmpty('bob',        true);
        assertIsNotEmpty('  bob  ',    true);
    }    
    
    private static void assertIsNotEmpty(String str, Boolean expected){
        Boolean actual = StringUtils.IsNotEmpty(str);
        System.assert(actual==expected, 'StringUtils.IsNotEmpty(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsAlpha(){
        //test: global static boolean isAlpha(String str) {
        assertIsAlpha(null, false);
        assertIsAlpha('', true);
        assertIsAlpha('  ', false);
        assertIsAlpha('abc', true);
        assertIsAlpha('ab2c', false);
        assertIsAlpha('ab-c', false);
    }

    private static void assertIsAlpha(String str, Boolean expected){
        Boolean actual = StringUtils.isAlpha(str);
        System.assert(actual==expected, 'StringUtils.isAlpha(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsAlphaSpace(){
        //test: global static boolean isAlphaSpace(String str) {
        assertIsAlphaSpace(null, false);
        assertIsAlphaSpace('', true);
        assertIsAlphaSpace('  ', true);
        assertIsAlphaSpace('abc', true);
        assertIsAlphaSpace('ab c', true);
        assertIsAlphaSpace('ab2c', false);
        assertIsAlphaSpace('ab-c', false);
    }

    private static void assertIsAlphaSpace(String str, Boolean expected){
        Boolean actual = StringUtils.isAlphaSpace(str);
        System.assert(actual==expected, 'StringUtils.isAlphaSpace(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsAlphanumeric(){
        //test: global static boolean isAlphanumeric(String str) {
        assertIsAlphanumeric(null, false);
        assertIsAlphanumeric('', true);
        assertIsAlphanumeric('  ', false);
        assertIsAlphanumeric('abc', true);
        assertIsAlphanumeric('ab c', false);
        assertIsAlphanumeric('ab2c', true);
        assertIsAlphanumeric('ab-c', false);
    }

    private static void assertIsAlphanumeric(String str, Boolean expected){
        Boolean actual = StringUtils.isAlphanumeric(str);
        System.assert(actual==expected, 'StringUtils.isAlphanumeric(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsAlphanumericSpace(){
        //test: global static boolean isAlphanumericSpace(String str) {
        assertIsAlphanumericSpace(null, false);
        assertIsAlphanumericSpace('', true);
        assertIsAlphanumericSpace('  ', true);
        assertIsAlphanumericSpace('abc', true);
        assertIsAlphanumericSpace('ab c', true);
        assertIsAlphanumericSpace('ab2c', true);
        assertIsAlphanumericSpace('ab-c', false);
    }

    private static void assertIsAlphanumericSpace(String str, Boolean expected){
        Boolean actual = StringUtils.isAlphanumericSpace(str);
        System.assert(actual==expected, 'StringUtils.isAlphanumericSpace(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsAsciiPrintable(){
        //test: global static boolean isAsciiPrintable(String str) {
        assertIsAsciiPrintable(null, false);
        assertIsAsciiPrintable('', true);
        assertIsAsciiPrintable(' ', true);
        assertIsAsciiPrintable('Ceki', true);
        assertIsAsciiPrintable('ab2c', true);
        assertIsAsciiPrintable('!ab-c~', true);
        assertIsAsciiPrintable(' ', true);
        assertIsAsciiPrintable('!', true);
        assertIsAsciiPrintable('~', true);
        assertIsAsciiPrintable('', false);
        assertIsAsciiPrintable('Ceki Gülcü', false);
    }

    private static void assertIsAsciiPrintable(String str, Boolean expected){
        Boolean actual = StringUtils.isAsciiPrintable(str);
        System.assert(actual==expected, 'StringUtils.isAsciiPrintable(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsNumeric(){
        //test: global static boolean isNumeric(String str) {
        assertIsNumeric(null, false);
        assertIsNumeric('', true);
        assertIsNumeric('  ', false);
        assertIsNumeric('123', true);
        assertIsNumeric('12 3', false);
        assertIsNumeric('ab2c', false);
        assertIsNumeric('12-3', false);
        assertIsNumeric('12.3', false);
    }

    private static void assertIsNumeric(String str, Boolean expected){
        Boolean actual = StringUtils.isNumeric(str);
        System.assert(actual==expected, 'StringUtils.isNumeric(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsNumericSpace(){
        //test: global static boolean isNumericSpace(String str) {
        assertIsNumericSpace(null, false);
        assertIsNumericSpace('', true);
        assertIsNumericSpace('  ', true);
        assertIsNumericSpace('123', true);
        assertIsNumericSpace('12 3', true);
        assertIsNumericSpace('ab2c', false);
        assertIsNumericSpace('12-3', false);
        assertIsNumericSpace('12.3', false);
    }

    private static void assertIsNumericSpace(String str, Boolean expected){
        Boolean actual = StringUtils.isNumericSpace(str);
        System.assert(actual==expected, 'StringUtils.isNumericSpace(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsWhitespace(){
        //test: global static boolean isWhitespace(String str) {
        assertIsWhitespace(null, false);
        assertIsWhitespace('', true);
        assertIsWhitespace('  ', true);
        assertIsWhitespace('abc', false);
        assertIsWhitespace('ab2c', false);
        assertIsWhitespace('ab-c', false);
    }

    private static void assertIsWhitespace(String str, Boolean expected){
        Boolean actual = StringUtils.isWhitespace(str);
        System.assert(actual==expected, 'StringUtils.isWhitespace(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testLength(){
        assertLength(null,         0);
        assertLength('',        0);
        assertLength(' ',        1);
        assertLength('bob',        3);
        assertLength('  bob  ',    7);
    }    
    
    private static void assertLength(String str, Integer expected){
        Integer actual = StringUtils.length(str);
        System.assert(actual==expected, 'StringUtils.length(\'' + str + '\') returned ' + actual);
    }

    private static testmethod void testIsBlank(){
        assertOnIsBlank(true, null);
        assertOnIsBlank(true, '');
        assertOnIsBlank(true, '     ');
        assertOnIsBlank(true, '\n');
        assertOnIsBlank(false, 'x');
        assertOnIsBlank(false, ' x');
        assertOnIsBlank(false, 'asdfasdfasdf ');
    }
    
    private static void assertOnIsBlank(Boolean expectedReturnValue, String theString){
        System.assert(StringUtils.isBlank(theString)==expectedReturnValue,
            'StringUtils.isBlank(\'' + (theString == null ? 'null' : theString) + '\') returned ' + !expectedReturnValue);
    }

    private static testmethod void testIsNotBlank(){
        assertOnIsNotBlank(false, null);
        assertOnIsNotBlank(false, '');
        assertOnIsNotBlank(false, '     ');
        assertOnIsNotBlank(false, '\n');
        assertOnIsNotBlank(true, 'x');
        assertOnIsNotBlank(true, ' x');
        assertOnIsNotBlank(true, 'asdfasdfasdf ');
    }
    
    private static void assertOnIsNotBlank(Boolean expectedReturnValue, String theString){
        System.assert(StringUtils.isNotBlank(theString)==expectedReturnValue,
            'StringUtils.isNotBlank(\'' + (theString == null ? 'null' : theString) + '\') returned ' + !expectedReturnValue);
    }
    
    private static testmethod void testTrim(){
        assertTrim(null, null);
        assertTrim('', '');
        assertTrim('a', 'a');
        assertTrim('\n', '');
        assertTrim('   ', '');
    }
    
    private static void assertTrim(String str, String expected){
        String actual = StringUtils.trim(str);
        System.assert(actual==expected, 'StringUtils.trim(\'' + str + '\') returned [' + actual + '], expected [' + expected + ']');
    }
     
    
    
    private static testmethod void testJoinStrings(){
        assertJoinStrings(null, null, null);
        assertJoinStrings(new Set<String>(), ':', null);
        assertJoinStrings(new Set<String>{'a','b','c'}, ':', 'a:c:b');
        assertJoinStrings(new Set<String>{' ','b','c'}, ':', 'c:b');
    }

    private static void assertJoinStrings(Set<String> strings, String separator, String expectedReturnValue){
        String actual = StringUtils.joinStrings(strings,separator);
        if(strings == null || strings.size() <= 0){
            System.assert(StringUtils.isBlank(expectedReturnValue), 'StringUtils.joinStrings(Set<String>, \'' + (separator == null ? 'null' : separator) + '\') returned ' + actual);
            return;
        }
        Set<String> actualAsSet = new Set<String>(StringUtils.split(actual,separator));
        Set<String> expectedAsSet = new Set<String>(StringUtils.split(expectedReturnValue,separator));
        System.debug('actualAsSet.containsAll(expectedAsSet): ' + actualAsSet.containsAll(expectedAsSet));
        System.debug('expectedAsSet.containsAll(actualAsSet): ' + expectedAsSet.containsAll(actualAsSet));
        System.assert(actualAsSet.containsAll(expectedAsSet) && expectedAsSet.containsAll(actualAsSet),
            'StringUtils.joinStrings(Set<String>, \'' + (separator == null ? 'null' : separator) + '\') returned ' + 
                actual + '; expected: ' + expectedReturnValue);
    }
    
    
    private static testmethod void testJoinStringsList(){
        assertJoinStringsList(null, null, null);
        assertJoinStringsList(new List<String>(), ':', null);
        assertJoinStringsList(new List<String>{'a','b','c'}, ':', 'a:c:b');
        assertJoinStringsList(new List<String>{' ','b','c'}, ':', 'c:b');
    }

    private static void assertJoinStringsList(List<String> strings, String separator, String expectedReturnValue){
        String actual = StringUtils.joinStrings(strings,separator);
        if(strings == null || strings.size() <= 0){
            System.assert(StringUtils.isBlank(expectedReturnValue), 'StringUtils.joinStrings(List<String>, \'' + (separator == null ? 'null' : separator) + '\') returned ' + actual);
            return;
        }
        Set<String> actualAsSet = new Set<String>(StringUtils.split(actual,separator));
        Set<String> expectedAsSet = new Set<String>(StringUtils.split(expectedReturnValue,separator));
        System.debug('actualAsSet.containsAll(expectedAsSet): ' + actualAsSet.containsAll(expectedAsSet));
        System.debug('expectedAsSet.containsAll(actualAsSet): ' + expectedAsSet.containsAll(actualAsSet));
        System.assert(actualAsSet.containsAll(expectedAsSet) && expectedAsSet.containsAll(actualAsSet),
            'StringUtils.joinStrings(List<String>, \'' + (separator == null ? 'null' : separator) + '\') returned ' + 
                actual + '; expected: ' + expectedReturnValue);
    }
    
    private static testmethod void testEndsWith(){
        assertEndsWith(null, null, true);
        assertEndsWith('abcdef', null, false);
        assertEndsWith(null, 'def', false);
        assertEndsWith('abcdef', 'def', true);
        assertEndsWith('ABCDEF', 'def', false);
    }

    private static testmethod void testEndsWithIgnoreCase(){
        assertEndsWithIgnoreCase(null, null, true);
        assertEndsWithIgnoreCase('abcdef', null, false);
        assertEndsWithIgnoreCase(null, 'def', false);
        assertEndsWithIgnoreCase('abcdef', 'def', true);
        assertEndsWithIgnoreCase('ABCDEF', 'def', true);
        assertEndsWithIgnoreCase('ABCDEF', 'ABCDEFA', false);
    }    
    
    private static void assertEndsWith(String str, String suffix, Boolean expected){
        Boolean actual = StringUtils.endsWith(str,suffix);
        System.assert(actual==expected, 'StringUtils.endsWith(\'' + str + '\',\'' + suffix + '\') returned ' + actual);
    }
    
    private static void assertEndsWithIgnoreCase(String str, String suffix, Boolean expected){
        Boolean actual = StringUtils.endsWithIgnoreCase(str,suffix);
        System.assert(actual==expected, 'StringUtils.endsWithIgnoreCase(\'' + str + '\',\'' + suffix + '\') returned ' + actual);
    }

    private static testmethod void testContains(){
        assertContains(null, null, false);
        assertContains('abcdef', null, false);
        assertContains(null, 'def', false);
        assertContains('abcdef', 'ab', true);
        assertContains('abcdef', 'xab', false);
        assertContains('ABCDEF', 'AB', true);
        assertContains('ABCDEF', 'Ab', false);

        assertContains('abcdef', 'ef', true);
        assertContains('abcdef', 'xef', false);
        assertContains('ABCDEF', 'EF', true);
        assertContains('ABCDEF', 'Ef', false);

        assertContains('abcdef', 'cde', true);
        assertContains('abcdef', 'xcde', false);
        assertContains('ABCDEF', 'CDE', true);
        assertContains('ABCDEF', 'CDe', false);
    }    
    
    private static void assertContains(String str, String searchStr, Boolean expected){
        Boolean actual = StringUtils.contains(str,searchStr);
        System.assert(actual==expected, 'StringUtils.contains(\'' + str + '\',\'' + searchStr + '\') returned ' + actual);
    }
    
    private static testmethod void testContainsIgnoreCase(){
        assertContainsIgnoreCase(null, null, false);
        assertContainsIgnoreCase('abcdef', null, false);
        assertContainsIgnoreCase(null, 'def', false);
        assertContainsIgnoreCase('abcdef', 'ab', true);
        assertContainsIgnoreCase('abcdef', 'xab', false);
        assertContainsIgnoreCase('ABCDEF', 'AB', true);
        assertContainsIgnoreCase('ABCDEF', 'Ab', true);
    }    
    
    private static void assertContainsIgnoreCase(String str, String searchStr, Boolean expected){
        Boolean actual = StringUtils.containsIgnoreCase(str,searchStr);
        System.assert(actual==expected, 'StringUtils.containsIgnoreCase(\'' + str + '\',\'' + searchStr + '\') returned ' + actual);
    }

    private static testmethod void testSplitOneArg(){
        assertSplitOneArg(null,         null);
        assertSplitOneArg('',             new String[]{''});
        assertSplitOneArg('abc def',     new String[]{'abc','def'});
        assertSplitOneArg('abc  def',     new String[]{'abc','def'});
        assertSplitOneArg(' abc ',         new String[]{'abc'});
    }    
    
    private static void assertSplitOneArg(String str, String[] expected){
        String[] actual = StringUtils.split(str);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.split(\'' + str + '\') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.split(\'' + str + '\') returned ' + ArrayUtils.toString(actual));
        }
    }
    
    private static testmethod void testSplitOneArgPreserveAllTokens(){
        assertSplitOneArgPreserveAllTokens(null,         null);
        assertSplitOneArgPreserveAllTokens('',             new String[]{''});
        assertSplitOneArgPreserveAllTokens('abc def',     new String[]{'abc','def'});
        assertSplitOneArgPreserveAllTokens('abc  def',     new String[]{'abc','','def'});
        assertSplitOneArgPreserveAllTokens(' abc ',     new String[]{'','abc',''});
        assertSplitOneArgPreserveAllTokens('a b c',     new String[]{'a','b','c'});
    }    
    
    private static void assertSplitOneArgPreserveAllTokens(String str, String[] expected){
        String[] actual = StringUtils.splitPreserveAllTokens(str);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitPreserveAllTokens(\'' + str + '\') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitPreserveAllTokens(\'' + str + '\') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testCharAt(){
        assertCharAt(null, -1, null);
        assertCharAt(null, 0, null);
        assertCharAt('abc', -1, null);
        assertCharAt('abc', 3, null);
        assertCharAt('abc', 0, 'a');
        assertCharAt('abc', 2, 'c');
        assertCharAt('abcde', -2, null);
        assertCharAt('abcde', 0, 'a');
        assertCharAt('abcde', 1, 'b');
        assertCharAt('abcde', 4, 'e');
        assertCharAt('abcde', 5, null);
        assertCharAt('', 0, '');
        assertCharAt(' ', 0, ' ');
    }    
    
    private static void assertCharAt(String str, Integer index, String expected){
        String actual = StringUtils.charAt(str,index);
        System.assert(actual==expected, 'StringUtils.charAt(\'' + str + '\',' + index + ') returned ' + actual);
    }
    
    private static testmethod void testSplitTwoArgs(){
        assertSplitTwoArgs(null,         null,     null);
        assertSplitTwoArgs('',             null,     new String[]{''});
        assertSplitTwoArgs('',             'abc',     new String[]{''});
        assertSplitTwoArgs('a.b.c',     '.',    new String[]{'a','b','c'});
        assertSplitTwoArgs('a..b.c',    '.',     new String[]{'a','b','c'});
        assertSplitTwoArgs('a..b..c',    '..',     new String[]{'a','b','c'});
        assertSplitTwoArgs('a:b:c',     '.',     new String[]{'a:b:c'});
        assertSplitTwoArgs('a b c',     ' ',     new String[]{'a','b','c'});
    }    

    private static void assertSplitTwoArgs(String str, String separator, String[] expected){
        String[] actual = StringUtils.split(str,separator);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.split(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.split(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testSplitThreeArgs(){
        assertSplitThreeArgs(null,             '',     1,     null);
        assertSplitThreeArgs('',             '',     1,     new String[]{''});
        assertSplitThreeArgs('ab cd ef',     null,     0,     new String[]{'ab', 'cd', 'ef'});
        assertSplitThreeArgs('ab   cd ef',     null,     0,     new String[]{'ab', 'cd', 'ef'});
        assertSplitThreeArgs('ab:cd:ef',     ':',     0,     new String[]{'ab', 'cd', 'ef'});
        assertSplitThreeArgs('ab:cd:ef',     ':',     2,     new String[]{'ab', 'cd:ef'});
    }    
    
    private static void assertSplitThreeArgs(String str, String separator, Integer max, String[] expected){
        String[] actual = StringUtils.split(str,separator,max);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.split(\'' + str + '\',\'' + separator + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.split(\'' + str + '\',\'' + separator + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
        }
    }
    
    private static testmethod void testSplitByWholeSeparatorTwoArg(){
        assertSplitByWholeSeparatorTwoArg(null,             null,     null);
        assertSplitByWholeSeparatorTwoArg('',                 null,    new String[]{''});
        assertSplitByWholeSeparatorTwoArg('ab cd ef',         null,    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorTwoArg('ab cd ef',         ' ',    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorTwoArg('ab     cd ef',     null,    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorTwoArg('ab:cd:ef',         ':',    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorTwoArg('ab-!-cd-!-ef',     '-!-',    new String[]{'ab', 'cd', 'ef'});
    }    
    
    private static void assertSplitByWholeSeparatorTwoArg(String str, String separator, String[] expected){
        String[] actual = StringUtils.splitByWholeSeparator(str,separator);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitByWholeSeparator(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitByWholeSeparator(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
        }
    }
    
    private static testmethod void testSplitPreserveAllTokensTwoArg(){
        //test global static String[] splitPreserveAllTokens(String str, String separatorChars) {
        assertSplitPreserveAllTokensTwoArg(null,             null,    null);
        assertSplitPreserveAllTokensTwoArg('',                 null,    new String[]{''});
        assertSplitPreserveAllTokensTwoArg('abc def',         null,    new String[]{'abc', 'def'});
        assertSplitPreserveAllTokensTwoArg('abc def',         ' ',    new String[]{'abc', 'def'});
        assertSplitPreserveAllTokensTwoArg('abc  def',         ' ',    new String[]{'abc', '', 'def'});
        assertSplitPreserveAllTokensTwoArg('ab:cd:ef',         ':',    new String[]{'ab', 'cd', 'ef'});
        assertSplitPreserveAllTokensTwoArg('ab:cd:ef:',     ':',    new String[]{'ab', 'cd', 'ef', ''});
        assertSplitPreserveAllTokensTwoArg('ab:cd:ef::',     ':',    new String[]{'ab', 'cd', 'ef', '', ''});
        assertSplitPreserveAllTokensTwoArg('ab::cd:ef',     ':',    new String[]{'ab', '', 'cd', 'ef'});
        assertSplitPreserveAllTokensTwoArg(':cd:ef',         ':',    new String[]{'', 'cd', 'ef'});
        assertSplitPreserveAllTokensTwoArg('::cd:ef',         ':',    new String[]{'', '', 'cd', 'ef'});
        assertSplitPreserveAllTokensTwoArg(':cd:ef:',         ':',    new String[]{'', 'cd', 'ef', ''});
    }

    private static void assertSplitPreserveAllTokensTwoArg(String str, String separator, String[] expected){
        String[] actual = StringUtils.splitPreserveAllTokens(str,separator);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitPreserveAllTokens(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitPreserveAllTokens(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testSplitPreserveAllTokensThreeArgs(){
        //test global static String[] splitPreserveAllTokens(String str, String separatorChars, Integer max) {
        assertSplitPreserveAllTokensThreeArgs(null,         null,    -1, null);
        assertSplitPreserveAllTokensThreeArgs('',             null,     -1,    new String[]{''});
        assertSplitPreserveAllTokensThreeArgs('ab cd ef',     null,     0,    new String[]{'ab', 'cd', 'ef'});
        assertSplitPreserveAllTokensThreeArgs('ab   cd ef', null,     0,    new String[]{'ab', '', '', 'cd', 'ef'});
        assertSplitPreserveAllTokensThreeArgs('ab:cd:ef',     ':',     0,    new String[]{'ab', 'cd', 'ef'});
        assertSplitPreserveAllTokensThreeArgs('ab:cd:ef',     ':',     2,    new String[]{'ab', 'cd:ef'});
        assertSplitPreserveAllTokensThreeArgs('ab::cd::ef', '::',     2,    new String[]{'ab', ':cd::ef'});
        assertSplitPreserveAllTokensThreeArgs('ab   de fg', null,     2,    new String[]{'ab', '  de fg'});
        assertSplitPreserveAllTokensThreeArgs('ab   de fg', null,     3,    new String[]{'ab', '', ' de fg'});
        assertSplitPreserveAllTokensThreeArgs('ab   de fg', null,     4,    new String[]{'ab', '', '', 'de fg'});
    }

    private static void assertSplitPreserveAllTokensThreeArgs(String str, String separatorChars, 
        Integer max, String[] expected){

        String[] actual = StringUtils.splitPreserveAllTokens(str,separatorChars,max);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitPreserveAllTokens(\'' + str + '\',\'' + separatorChars + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitPreserveAllTokens(\'' + str + '\',\'' + separatorChars + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testSplitByWholeSeparatorThreeArgs(){
        //test global static String[] splitByWholeSeparator(String str, String separator, Integer max ) {
        
        assertTestSplitByWholeSeparatorThreeArgs(null,             null,     0, null);
        assertTestSplitByWholeSeparatorThreeArgs('',                 null,    0, new String[]{''});
        assertTestSplitByWholeSeparatorThreeArgs('ab cd ef',         null,    0, new String[]{'ab', 'cd', 'ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab cd ef',         ' ',    0, new String[]{'ab', 'cd', 'ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab     cd ef',     null,    0, new String[]{'ab', 'cd', 'ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab:cd:ef',         ':',    1, new String[]{'ab:cd:ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab:cd:ef',         ':',    2, new String[]{'ab', 'cd:ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab:cd:ef',         ':',    3, new String[]{'ab', 'cd', 'ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab-!-cd-!-ef',     '-!-',    5, new String[]{'ab', 'cd', 'ef'});
        assertTestSplitByWholeSeparatorThreeArgs('ab-!-cd-!-ef',     '-!-',    2, new String[]{'ab', 'cd-!-ef'});
    }
    private static void assertTestSplitByWholeSeparatorThreeArgs(String str, String separator, 
        Integer max, String[] expected){

        String[] actual = StringUtils.splitByWholeSeparator(str,separator,max);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitByWholeSeparator(\'' + str + '\',\'' + separator + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitByWholeSeparator(\'' + str + '\',\'' + separator + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testSplitByWholeSeparatorPreserveAllTokensTwoArgs(){
        //test global static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator) {
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs(null,             null,     null);
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('',             null,    new String[]{''});
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('ab cd ef',     null,    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('ab cd ef',     ' ',    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('ab   cd ef',     null,    new String[]{'ab', '', '', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('ab:cd:ef',     ':',    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('ab-!-cd-!-ef', '-!-',    new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensTwoArgs('ab-!--!-cd-!-ef','-!-',    new String[]{'ab', '', 'cd', 'ef'});
    }
    private static void assertSplitByWholeSeparatorPreserveAllTokensTwoArgs(String str, String separator, String[] expected){

        String[] actual = StringUtils.splitByWholeSeparatorPreserveAllTokens(str,separator);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitByWholeSeparatorPreserveAllTokens(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitByWholeSeparatorPreserveAllTokens(\'' + str + '\',\'' + separator + '\') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testSplitByWholeSeparatorPreserveAllTokensThreeArgs(){
        //test global static String[] splitByWholeSeparatorPreserveAllTokens(String str, String separator, Integer max) {

        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs(null,                 null,     0, null);
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('',                 null,    0, new String[]{''});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab cd ef',         null,    0, new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab cd ef',         ' ',    0, new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab   cd ef',         ' ',    0, new String[]{'ab', '', '', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab:cd:ef',         ':',    1, new String[]{'ab:cd:ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab:cd:ef',         ':',    2, new String[]{'ab', 'cd:ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab:cd:ef',         ':',    3, new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab::cd:ef',         ':',    2, new String[]{'ab', ':cd:ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab-!-cd-!-ef',     '-!-',    5, new String[]{'ab', 'cd', 'ef'});
        assertSplitByWholeSeparatorPreserveAllTokensThreeArgs('ab-!-cd-!-ef',     '-!-',    2, new String[]{'ab', 'cd-!-ef'});
    }
    private static void assertSplitByWholeSeparatorPreserveAllTokensThreeArgs(String str, String separator, 
        Integer max, String[] expected){

        String[] actual = StringUtils.splitByWholeSeparatorPreserveAllTokens(str,separator,max);
        if(actual == null){
            System.assert(expected == null, 'StringUtils.splitByWholeSeparatorPreserveAllTokens(\'' + str + '\',\'' + separator + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
            return;
        }
        for(Integer i = 0; i < actual.size(); i++){
            System.assert(expected[i] == actual[i], 'StringUtils.splitByWholeSeparatorPreserveAllTokens(\'' + str + '\',\'' + separator + '\',' + max + ') returned ' + ArrayUtils.toString(actual));
        }
    }

    private static testmethod void testLeftPadTwoArgs(){
        // test: global static String leftPad(String str, Integer size) {
        assertLeftPadTwoArgs(null,     -1,    null);
        assertLeftPadTwoArgs('',     3,     '   ');
        assertLeftPadTwoArgs('bat', 3,     'bat');
        assertLeftPadTwoArgs('bat', 5,     '  bat');
        assertLeftPadTwoArgs('bat', 1,    'bat');
        assertLeftPadTwoArgs('bat', -1,    'bat');
    }    
    
    private static void assertLeftPadTwoArgs(String str, Integer size, String expected){
        String actual = StringUtils.leftPad(str,size);
        System.assert(actual==expected, 'StringUtils.leftPad(\'' + str + '\',' 
            + size + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testLeftPadThreeArgs(){
        //test: global static String leftPad(String str, Integer size, String padStr) {
        assertLeftPadThreeArgs(null,     -1, null,     null);
        assertLeftPadThreeArgs('',         3,     'z',     'zzz'); 
        assertLeftPadThreeArgs('bat',     3,     'yz',     'bat');
        assertLeftPadThreeArgs('bat',     5,     'yz',     'yzbat');
        assertLeftPadThreeArgs('bat',     8,     'yz',     'yzyzybat');
        assertLeftPadThreeArgs('bat',     1,     'yz',     'bat');
        assertLeftPadThreeArgs('bat',     -1, 'yz',     'bat');
        assertLeftPadThreeArgs('bat',     5,     null,     '  bat');
        assertLeftPadThreeArgs('bat',     5,     '',     '  bat');
    }    

    private static void assertLeftPadThreeArgs(String str, Integer size, String padStr, String expected){
        String actual = StringUtils.leftPad(str,size,padStr);
        System.assert(actual==expected, 'StringUtils.leftPad(\'' + str + '\',' 
            + size + ',\'' + padStr + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testRightPadTwoArgs(){
        //test: global static String rightPad(String str, Integer size) {
        assertRightPadTwoArgs(null,     -1, null);
        assertRightPadTwoArgs('',         3,     '   ');
        assertRightPadTwoArgs('bat',     3,     'bat');
        assertRightPadTwoArgs('bat',     5,     'bat  ');
        assertRightPadTwoArgs('bat',     1,     'bat');
        assertRightPadTwoArgs('bat',     -1, 'bat');
    }    
    
    private static void assertRightPadTwoArgs(String str, Integer size, String expected){
        String actual = StringUtils.rightPad(str,size);
        System.assert(actual==expected, 'StringUtils.rightPad(\'' + str + '\',' 
            + size + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testRightPadThreeArgs(){
        //test: global static String rightPad(String str, Integer size, String padStr) {
        assertRightPadThreeArgs(null,     -1, null,     null);
        assertRightPadThreeArgs('',     3,     '',     '   ');
        assertRightPadThreeArgs('',     3,     'z',     'zzz');
        assertRightPadThreeArgs('bat',     3,     'z',     'bat');
        assertRightPadThreeArgs('bat',     5,     'z',     'batzz');
        assertRightPadThreeArgs('bat',     1,     'z',     'bat');
        assertRightPadThreeArgs('bat',     -1,    'z',     'bat');
        assertRightPadThreeArgs('bat',     6,    'abcd', 'batabc');
    }    
    
    private static void assertRightPadThreeArgs(String str, Integer size, String padStr, String expected){
        String actual = StringUtils.rightPad(str,size,padStr);
        System.assert(actual==expected, 'StringUtils.rightPad(\'' + str + '\',' 
            + size + ',\'' + padStr + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }

    private static testmethod void testGetCommonPrefix(){
        //test: global static String getCommonPrefix(List<String> strs) {
        assertGetCommonPrefix(null,                                             '');
        assertGetCommonPrefix(null,                                             '');
        assertGetCommonPrefix(new String[] {},                                     '');
        assertGetCommonPrefix(new String[] {'abc'},                             'abc');
        assertGetCommonPrefix(new String[] {null, null},                         '');
        assertGetCommonPrefix(new String[] {'', ''},                             '');
        assertGetCommonPrefix(new String[] {'', null},                             '');
        assertGetCommonPrefix(new String[] {'abc', null, null},                 '');
        assertGetCommonPrefix(new String[] {null, null, 'abc'},                 '');
        assertGetCommonPrefix(new String[] {'', 'abc'},                         '');
        assertGetCommonPrefix(new String[] {'abc', ''},                         '');
        assertGetCommonPrefix(new String[] {'abc', 'abc'},                         'abc');
        assertGetCommonPrefix(new String[] {'abc', 'a'},                         'a');
        assertGetCommonPrefix(new String[] {'ab', 'abxyz'},                     'ab');
        assertGetCommonPrefix(new String[] {'abcde', 'abxyz'},                     'ab');
        assertGetCommonPrefix(new String[] {'abcde', 'xyz'},                     '');
        assertGetCommonPrefix(new String[] {'xyz', 'abcde'},                     '');
        assertGetCommonPrefix(new String[] {'i am a machine', 'i am a robot'},     'i am a ');
    }    
    
    private static void assertGetCommonPrefix(String[] strs, String expected){
        String actual = StringUtils.getCommonPrefix(strs);
        System.assert(actual==expected, 'StringUtils.getCommonPrefix(' + ArrayUtils.toString(strs) 
            + ') returned \'' + actual + '\', expected \'' + expected + '\'');
    }

    private static testmethod void testIndexOfDifferenceArrayInput(){
        //test: global static Integer indexOfDifference(String[] strs) {
        assertIndexOfDifferenceArrayInput(null,                                             -1);
        assertIndexOfDifferenceArrayInput(new String[] {},                                     -1);
        assertIndexOfDifferenceArrayInput(new String[] {'abc'},                             -1);
        assertIndexOfDifferenceArrayInput(new String[] {null, null},                         -1);
        assertIndexOfDifferenceArrayInput(new String[] {'', ''},                             -1);
        assertIndexOfDifferenceArrayInput(new String[] {'', null},                             0);
        assertIndexOfDifferenceArrayInput(new String[] {'abc', null, null},                 0);
        assertIndexOfDifferenceArrayInput(new String[] {null, null, 'abc'},                 0);
        assertIndexOfDifferenceArrayInput(new String[] {'', 'abc'},                         0);
        assertIndexOfDifferenceArrayInput(new String[] {'abc', ''},                            0);
        assertIndexOfDifferenceArrayInput(new String[] {'abc', 'abc'},                         -1);
        assertIndexOfDifferenceArrayInput(new String[] {'abc', 'a'},                         1);
        assertIndexOfDifferenceArrayInput(new String[] {'ab', 'abxyz'},                     2);
        assertIndexOfDifferenceArrayInput(new String[] {'abcde', 'abxyz'},                     2);
        assertIndexOfDifferenceArrayInput(new String[] {'abcde', 'xyz'},                     0);
        assertIndexOfDifferenceArrayInput(new String[] {'xyz', 'abcde'},                     0);
        assertIndexOfDifferenceArrayInput(new String[] {'i am a machine', 'i am a robot'},     7);
    }    
    
    private static void assertIndexOfDifferenceArrayInput(String[] strs, Integer expected){
        Integer actual = StringUtils.indexOfDifference(strs);
        System.assert(actual==expected, 'StringUtils.indexOfDifference(' + ArrayUtils.toString(strs) 
            + ') returned ' + actual + '; expected ' + expected);
    }


    private static testmethod void testGetLevenshteinDistance(){
        //test: global static Integer getLevenshteinDistance(String s, String t) {
        assertGetLevenshteinDistance(null,             null,         -1,    true);
        assertGetLevenshteinDistance(null,             null,         -1,    true);
        assertGetLevenshteinDistance('',            '',         0,    false);
        assertGetLevenshteinDistance('',            'a',         1,    false);
        assertGetLevenshteinDistance('aaapppp',     '',         7,    false);
        assertGetLevenshteinDistance('frog',         'fog',         1,    false);
        assertGetLevenshteinDistance('fly',         'ant',         3,    false);
        assertGetLevenshteinDistance('elephant',     'hippo',     7,    false);
        assertGetLevenshteinDistance('hippo',         'elephant', 7,    false);
        assertGetLevenshteinDistance('hippo',         'zzzzzzzz', 8,    false);
        assertGetLevenshteinDistance('hello',         'hallo',     1,    false);
    }    
    
    private static void assertGetLevenshteinDistance(String s, String t, 
        Integer expected, Boolean excepExpected){

        Integer actual = null;
        Boolean excepActual = false;
        try{
            actual = StringUtils.getLevenshteinDistance(s,t);
        } catch (IllegalArgumentException e){
            excepActual = true;
        }
        if(excepExpected && excepActual){
            return;
        }
        System.assert(excepExpected == excepActual, 'StringUtils.getLevenshteinDistance(\'' 
            + s + '\',\'' + t + '\') ' 
            + (excepExpected ? 'did not throw' : 'unexpectedly threw') 
            + ' IllegalArgumentException');
        if(!excepExpected && !excepActual){
            System.assert(actual==expected, 'StringUtils.getLevenshteinDistance(\'' + s + '\',\'' 
                + t + '\') returned ' + actual + '; expected ' + expected);
        }
    }


     private static testmethod void testIndexOfThreeArgs(){
        //test: global static Integer indexOf(String str, String searchStr, Integer startPos) {
        assertIndexOfThreeArgs(null,         null,     -1, -1);
        assertIndexOfThreeArgs('',             '',     0,     0);
        assertIndexOfThreeArgs('aabaabaa',     'a',     0,     0);
        assertIndexOfThreeArgs('aabaabaa',     'b',     0,     2);
        assertIndexOfThreeArgs('aabaabaa',     'ab',     0,     1);
        assertIndexOfThreeArgs('aabaabaa',     'b',     3,     5);
        assertIndexOfThreeArgs('aabaabaa',     'b',     9,     -1);
        assertIndexOfThreeArgs('aabaabaa',     'b',     -1, 2);
        assertIndexOfThreeArgs('aabaabaa',     '',     2,     2);
        assertIndexOfThreeArgs('abc',         '',     9,     3);
    }    

    private static void assertIndexOfThreeArgs(String str, String searchStr, Integer startPos, Integer expected){
        Integer actual = StringUtils.indexOf(str,searchStr,startPos);
        System.assert(actual==expected, 'StringUtils.indexOf(\'' + str + '\',\'' 
            + searchStr + '\',' + startPos + ') returned ' + actual + '; expected ' + expected);
    }

    private static testmethod void testOrdinalIndexOf(){
        //test: global static Integer ordinalIndexOf(String str, String searchStr, Integer ordinal) {
        assertOrdinalIndexOf(null,             null,     -1, -1);
        assertOrdinalIndexOf('',             '',     -1, -1);
        assertOrdinalIndexOf('aabaabaa',     'a',     1,     0);
        assertOrdinalIndexOf('aabaabaa',     'a',     2,     1);
        assertOrdinalIndexOf('aabaabaa',     'b',     1,     2);
        assertOrdinalIndexOf('aabaabaa',     'b',     2,     5);
        assertOrdinalIndexOf('aabaabaa',     'ab',     1,     1);
        assertOrdinalIndexOf('aabaabaa',     'ab',     2,     4);
        assertOrdinalIndexOf('aabaabaa',     'z',     1,     -1);
        assertOrdinalIndexOf('aabaabaa',     '',     1,     0);
        assertOrdinalIndexOf('aabaabaa',     '',     2,     0);
    }    

    private static void assertOrdinalIndexOf(String str, String searchStr, Integer ordinal, Integer expected){
        Integer actual = StringUtils.ordinalIndexOf(str,searchStr,ordinal);
        System.assert(actual==expected, 'StringUtils.ordinalIndexOf(\'' + str + '\',\'' 
            + searchStr + '\',' + ordinal + ') returned ' + actual + '; expected ' + expected);
    }

    private static testmethod void testValidateChar(){
        try{
            Character.validateChar('ab');  //should throw exception since string has > 1 chars
            System.assert(false,'Character.validateChar(\'ab\') did not throw InvalidCharacterStringException');
        }catch(InvalidCharacterStringException e){}
    }

    private static testmethod void testJoinArrayOneArg(){
        //test: global static String joinArray(Object[] objectArray) {
        assertJoinArrayOneArg(null, null);
        assertJoinArrayOneArg(new String[]{}, '');
        assertJoinArrayOneArg(new String[]{null}, '');
        assertJoinArrayOneArg(new String[]{'a', 'b', 'c'}, 'abc');
        assertJoinArrayOneArg(new String[]{null, '', 'a'}, 'a');
    }
    
    private static void assertJoinArrayOneArg(Object[] objectArray, String expected){
        String actual = StringUtils.joinArray(objectArray);
        System.assert(actual==expected, 'StringUtils.joinArray(\'' + ArrayUtils.toString(objectArray) + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }

    private static testmethod void testJoinArrayTwoArgs(){
        //test: global static String joinArray(Object[] objectArray, String separator) {
        assertJoinArrayTwoArgs(null, null, null);
        assertJoinArrayTwoArgs(new String[]{}, null, '');
        assertJoinArrayTwoArgs(new String[]{null}, null, '');
        assertJoinArrayTwoArgs(new String[]{'a', 'b', 'c'}, ';', 'a;b;c');
        assertJoinArrayTwoArgs(new String[]{'a', 'b', 'c'}, null, 'abc');
        assertJoinArrayTwoArgs(new String[]{null, '', 'a'}, ';', ';;a');
    }
    
    private static void assertJoinArrayTwoArgs(Object[] objectArray, String separator, String expected){
        String actual = StringUtils.joinArray(objectArray,separator);
        System.assert(actual==expected, 'StringUtils.joinArray(\'' + ArrayUtils.toString(objectArray) + '\',\''
            + separator + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }

    private static testmethod void testJoinArrayFourArgs(){
        //test: global static String joinArray(Object[] objectArray, String separator, Integer startIndex, Integer endIndex) {
        assertJoinArrayFourArgs(null, null, 0, 2, null);
        assertJoinArrayFourArgs(new String[]{}, null, 0, 1, '');
        assertJoinArrayFourArgs(new String[]{null}, null, 0, 1, '');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '--', 0, 3, 'a--b--c');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, null, 0, 3, 'abc');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 0, 0, '');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 0, 1, 'a');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 0, 2, 'ab');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 0, 3, 'abc');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', -1, 4, 'abc');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 1, 1, '');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 1, 2, 'b');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 1, 3, 'bc');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 2, 2, '');
        assertJoinArrayFourArgs(new String[]{'a', 'b', 'c'}, '', 2, 3, 'c');
        assertJoinArrayFourArgs(new String[]{null, '', 'a'}, ',', 0, 3, ',,a');
        assertJoinArrayFourArgs(new Long[]{3, 4, -1}, 'xyz', 0, 3, '3xyz4xyz-1');
    }

    private static void assertJoinArrayFourArgs(Object[] objectArray, String separator, Integer startIndex, Integer endIndex, String expected){
        String actual = StringUtils.joinArray(objectArray,separator,startIndex,endIndex);
        System.assert(actual==expected, 'StringUtils.joinArray(\'' + ArrayUtils.toString(objectArray) + '\',\''
            + separator + '\',' + startIndex + ',' + endIndex + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }

     private static testmethod void testJoinSetBlobSet(){ 
        //global static String joinSet(Set<Blob> blobSet, String separator)
        assertJoinSetBlobSet(null, '|', null);
        assertJoinSetBlobSet(new Set<Blob>{}, '|', '');
        Blob blob1 = generateRandomBlob();
        Blob blob2 = generateRandomBlob();
        assertJoinSetBlobSet(new Set<Blob>{blob1}, '|', '\'' + blob1.toString() + '\'');
        assertJoinSetBlobSet(new Set<Blob>{blob1,blob2}, '|', '\'' + blob1.toString() + '\'|\'' + blob2.toString() + '\'');
    }    

    private static testmethod void testJoinSetBooleanSet(){ 
        //global static String joinSet(Set<Boolean> booleanSet, String separator) 
        assertJoinSetBooleanSet(null, '|', null);
        assertJoinSetBooleanSet(new Set<Boolean>{}, '|', '');
        assertJoinSetBooleanSet(new Set<Boolean>{true}, '|', 'true');
        assertJoinSetBooleanSet(new Set<Boolean>{true, false}, '|', 'false|true');
    }
    
    private static testmethod void testJoinSetDateSet(){ 
        //global static String joinSet(Set<Date> dateSet, String separator) 
        assertJoinSetDateSet(null, '|', null);
        assertJoinSetDateSet(new Set<Date>{}, '|', '');
        Date date1 = Date.newInstance(2009,1,1);
        Date date2 = Date.newInstance(2009,1,2);
        assertJoinSetDateSet(new Set<Date>{date1}, '|', ''+date1+'' );
        assertJoinSetDateSet(new Set<Date>{date1,date2}, '|', ''+date1+'|'+date2+'' );
    }
    
    private static testmethod void testJoinSetDatetimeSet(){ 
        //global static String joinSet(Set<Datetime> datetimeSet, String separator) 
        assertJoinSetDatetimeSet(null, '|', null);
        assertJoinSetDatetimeSet(new Set<Datetime>{}, '|', '');
        Datetime date1 = Datetime.newInstance(2009,1,1);
        Datetime date2 = Datetime.newInstance(2009,1,2);
        assertJoinSetDatetimeSet(new Set<Datetime>{date1}, '|', ''+date1+'' );
        assertJoinSetDatetimeSet(new Set<Datetime>{date1,date2}, '|', ''+date1+'|'+date2+'' );
    }
    
    private static testmethod void testJoinSetDecimalSet(){ 
        //global static String joinSet(Set<Decimal> decimalSet, String separator) 
        assertJoinSetDecimalSet(null, '|', null);
        assertJoinSetDecimalSet(new Set<Decimal>{}, '|', '');
        Decimal dec1 = 4.0;
        Decimal dec2 = 5.0;
        assertJoinSetDecimalSet(new Set<Decimal>{dec1}, '|', '' + dec1 + '');
        assertJoinSetDecimalSet(new Set<Decimal>{dec1,dec2}, '|', '' + dec1 + '|' + dec2 + '');
    }
    
    private static testmethod void testJoinSetDoubleSet(){ 
        //global static String joinSet(Set<Double> doubleSet, String separator) 
        assertJoinSetDoubleSet(null, '|', null);
        assertJoinSetDoubleSet(new Set<Double>{}, '|', '');
        Double doub1 = 4.0;
        Double doub2 = 5.0;
        assertJoinSetDoubleSet(new Set<Double>{doub1}, '|', '' + doub1 + '');
        assertJoinSetDoubleSet(new Set<Double>{doub1,doub2}, '|', '' + doub1 + '|' + doub2 + '');
    }
    
    private static testmethod void testJoinSetIDSet(){ 
        //global static String joinSet(Set<ID> idSet, String separator) 
        assertJoinSetIDSet(null, '|', null);
        assertJoinSetIDSet(new Set<ID>{}, '|', '');
        Account acct1 = new Account(name='acct1');
        insert acct1;
        Account acct2 = new Account(name='acct2');
        insert acct2;
        assertJoinSetIDSet(new Set<ID>{acct1.id}, '|', '' + acct1.id + '');
        assertJoinSetIDSet(new Set<ID>{acct1.id,acct2.id}, '|', '' + acct1.id + '|' + acct2.id + '');
    }
    
    private static testmethod void testJoinSetIntegerSet(){ 
        //global static String joinSet(Set<Integer> integerSet, String separator) 
        assertJoinSetIntegerSet(null, '|', null);
        assertJoinSetIntegerSet(new Set<Integer>{}, '|', '');
        Integer int1 = 4;
        Integer int2 = 5;
        assertJoinSetIntegerSet(new Set<Integer>{int1}, '|', '' + int1 + '' );
        assertJoinSetIntegerSet(new Set<Integer>{int1,int2}, '|', '' + int1 + '|' + int2 + '' );
    }
    
    private static testmethod void testJoinSetLongSet(){ 
        //global static String joinSet(Set<Long> longSet, String separator) 
        assertJoinSetLongSet(null, '|', null);
        assertJoinSetLongSet(new Set<Long>{}, '|', '');
        Long long1 = 4;
        Long long2 = 5;
        assertJoinSetLongSet(new Set<Long>{long1}, '|', '' + long1 + '');
        assertJoinSetLongSet(new Set<Long>{long1,long2}, '|', '' + long1 + '|' + long2 + '');
    }
    
    private static testmethod void testJoinSetTimeSet(){ 
        //global static String joinSet(Set<Time> timeSet, String separator) 
        assertJoinSetTimeSet(null, '|', null);
        assertJoinSetTimeSet(new Set<Time>{}, '|', '');
        Time time1 = Time.newInstance(18, 30, 2, 20);
        Time time2 = Time.newInstance(18, 30, 2, 21);
        assertJoinSetTimeSet(new Set<Time>{time1}, '|', '' + time1 + '' );
        assertJoinSetTimeSet(new Set<Time>{time1,time2}, '|', '' + time1 + '|' + time2 + '' );
    }
    
    private static testmethod void testJoinSetStringSet(){ 
        //global static String joinSet(Set<String> stringSet, String separator) 
        assertJoinSetStringSet(null, '|', null);
        assertJoinSetStringSet(new Set<String>{}, '|', '');
        String str1 = 'xyz';
        String str2 = 'abc';
        assertJoinSetStringSet(new Set<String>{str1}, '|', '' + str1 + '');
        assertJoinSetStringSet(new Set<String>{str1,str2}, '|', '' + str1 + '|' + str2 + '');
    }
    
    private static void assertJoinSetBlobSet(Set<Blob> blobSet, String separator, String expected){ System.assert(!((blobSet == null && expected != null) || (blobSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(blobSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(blobSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetBooleanSet(Set<Boolean> booleanSet, String separator, String expected){ System.assert(!((booleanSet == null && expected != null) || (booleanSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(booleanSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(booleanSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetDateSet(Set<Date> dateSet, String separator, String expected){ System.assert(!((dateSet == null && expected != null) || (dateSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(dateSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(dateSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetDatetimeSet(Set<Datetime> datetimeSet, String separator, String expected){ System.assert(!((datetimeSet == null && expected != null) || (datetimeSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(datetimeSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(datetimeSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetDecimalSet(Set<Decimal> decimalSet, String separator, String expected){ System.assert(!((decimalSet == null && expected != null) || (decimalSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(decimalSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(decimalSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetDoubleSet(Set<Double> doubleSet, String separator, String expected){ System.assert(!((doubleSet == null && expected != null) || (doubleSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(doubleSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(doubleSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetIDSet(Set<ID> idSet, String separator, String expected){ System.assert(!((idSet == null && expected != null) || (idSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(idSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(idSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetIntegerSet(Set<Integer> integerSet, String separator, String expected){ System.assert(!((integerSet == null && expected != null) || (integerSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(integerSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(integerSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetLongSet(Set<Long> longSet, String separator, String expected){ System.assert(!((longSet == null && expected != null) || (longSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(longSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(longSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetTimeSet(Set<Time> timeSet, String separator, String expected){ System.assert(!((timeSet == null && expected != null) || (timeSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(timeSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(timeSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}
    private static void assertJoinSetStringSet(Set<String> stringSet, String separator, String expected){ System.assert(!((stringSet == null && expected != null) || (stringSet != null && expected == null)),    'Invalid test input: both parameters should be null.');String actual = StringUtils.joinSet(stringSet,separator); Set<String> actualAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars(    (actual == null ? '' : actual),'{}\'',''),separator));Set<String> expectedAsStringSet = new Set<String>(StringUtils.split(StringUtils.replaceChars((expected == null ? '' : expected),'{}\'',''),separator));     if(expected != null && actual != null){System.assert(actualAsStringSet.containsAll(expectedAsStringSet) && expectedAsStringSet.containsAll(actualAsStringSet), 'StringUtils.joinSet(' +     SetUtils.toString(stringSet) + ') returned \'' + actual + '\'; expected \'' + expected + '\'');}}

    private static Blob generateRandomBlob(){
        return EncodingUtil.base64Decode(''+System.currentTimeMillis()+Math.roundToLong(Math.random()*10000));    
    }

    private static testmethod void testReplaceChars(){
        //test: global static String replaceChars(String str, String searchChars, String replaceChars)
        assertReplaceChars(null, null, null, null);
        assertReplaceChars('', null, null, '');
        assertReplaceChars('abc', null, null, 'abc');
        assertReplaceChars('abc', '', null, 'abc');
        assertReplaceChars('abc', 'b', null, 'ac');
        assertReplaceChars('abc', 'b', '', 'ac');
        assertReplaceChars('abcba', 'bc', 'yz', 'ayzya');
        assertReplaceChars('abcba', 'bc', 'y', 'ayya');
        assertReplaceChars('abcba', 'bc', 'yzx', 'ayzya');
    }    
    
    private static void assertReplaceChars(String str, String searchChars, String replaceChars, String expected){
        String actual = StringUtils.replaceChars(str,searchChars,replaceChars);
        System.assert(actual==expected, 'StringUtils.replaceChars(\'' + str + '\',\'' 
            + searchChars + '\',\'' + replaceChars + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testJoinSet(){
        //test: global static String joinSet(Set<Object> objectSet, String separator){
        assertJoinSet(null, null, null);
        assertJoinSet(new Set<Object>(), ':', null);
        assertJoinSet(new Set<Object>{'a','b','c'}, ':', 'a:c:b');
        assertJoinSet(new Set<Object>{' ','b','c'}, ':', 'c:b');
        assertJoinSet(new Set<Object>{true,false}, '|', 'true|false');
    }

    private static void assertJoinSet(Set<Object> objectSet, String separator, String expected){
        String actual = StringUtils.joinSet(objectSet,separator);
        if(objectSet == null || objectSet.size() <= 0){
            System.assert(StringUtils.isBlank(expected), 
                'StringUtils.joinSet(Set<Object>, \'' + (separator == null ? 'null' : separator) 
                + '\') returned \'' + actual + '\'; expected \'' + expected + '\'');
            return;
        }
        Set<String> actualAsSet = new Set<String>(StringUtils.split(actual,separator));
        Set<String> expectedAsSet = new Set<String>(StringUtils.split(expected,separator));
        System.assert(actualAsSet.containsAll(expectedAsSet) && expectedAsSet.containsAll(actualAsSet),
            'StringUtils.joinSet(Set<Object>, \'' + (separator == null ? 'null' : separator) + '\') returned \'' + 
                actual + '\'; expected \'' + expected + '\'');
    }

    private static testmethod void testSubstringTwoArgs(){
        //test: global static String substring(String str, Integer startIndex) {
        assertSubstringTwoArgs(null, -1, null);
        assertSubstringTwoArgs('', -2, '');
        assertSubstringTwoArgs('', -1, '');
        assertSubstringTwoArgs('', 0, '');
        assertSubstringTwoArgs('', 1, '');
        assertSubstringTwoArgs('abc', 0, 'abc');
        assertSubstringTwoArgs('abc', 2, 'c');
        assertSubstringTwoArgs('abc', 4, '');
        assertSubstringTwoArgs('abc', -2, 'bc');
        assertSubstringTwoArgs('abc', -4, 'abc');
    }

    private static void assertSubstringTwoArgs(String str, Integer startIndex, String expected){
        String actual = StringUtils.substring(str, startIndex);
        System.assert(actual==expected, 'StringUtils.substring(\'' + str + '\',' 
            + startIndex + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
    private static testmethod void testSubstringThreeArgs(){
        //test: global static String substring(String str, Integer startIndex, Integer endIndex) {
        assertSubstringThreeArgs(null, -1, -1, null);
        assertSubstringThreeArgs('', -1, -1, '');
        assertSubstringThreeArgs('abc', 0, 2, 'ab');
        assertSubstringThreeArgs('abc', 2, 0, '');
        assertSubstringThreeArgs('abc', 2, 4, 'c');
        assertSubstringThreeArgs('abc', 4, 6, '');
        assertSubstringThreeArgs('abc', 2, 2, '');
        assertSubstringThreeArgs('abc', -2, -1, 'b');
        assertSubstringThreeArgs('abc', -4, 2, 'ab');
        assertSubstringThreeArgs('abc', -5, -4, '');
        
    }
    
    private static void assertSubstringThreeArgs(String str, Integer startIndex, Integer endIndex, String expected){
        String actual = StringUtils.substring(str, startIndex, endIndex);
        System.assert(actual==expected, 'StringUtils.substring(\'' + str + '\',' 
            + startIndex + ',' + endIndex + ') returned \'' + actual + '\'; expected \'' + expected + '\'');
    }
    
}